package cn.parus.dynamicRouter.component;

import cn.parus.dynamicRouter.Filter.DynamicRouteFilter;
import cn.parus.dynamicRouter.dao.Repository.ApiRepository;
import cn.parus.dynamicRouter.entity.ApiInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.route.Route;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.stereotype.Component;
import org.springframework.web.util.UriComponentsBuilder;
import reactor.core.publisher.Flux;

import java.net.URI;
import java.util.List;

/**
 * @Author: Axel
 * @Description: TODO 实现RouteLcatior,一次性刷新全量的API信息，实现动态加载
 **/
@Component
@Slf4j
public class RefreshRouteLocator implements RouteLocator {
    /**
     * 获取刷新日志
     */

    private Flux<Route> route;
    private RouteLocatorBuilder builder;
    private RouteLocatorBuilder.Builder routesBuilder;

    /**
     * 构造方法
     * 刷新可用的路由实例，可以直接用于路由
     * @param builder
     */
    public RefreshRouteLocator(RouteLocatorBuilder builder) {
        this.builder = builder;
        clearRoutes();
    }

    @Autowired
    GatewayRoutesRefresher gatewayRoutesRefresher;
    @Autowired
    private ApiRepository apiRepository;
    @Autowired
    DynamicRouteFilter dynamicRouteFilter;

    /**
     * 清除所有的路由
     */
    public void clearRoutes() {
        routesBuilder = builder.routes();
    }

    /**
     * 获取路由
     * @return
     */
    @Override
    public Flux<Route> getRoutes() {
        return route != null ? route : Flux.empty();
    }

    /**
     * 配置完成后，调用本方法构建路由和刷新路由表
     * 保证线程apiRepository.get(serviceId)或者routesBuilder.route()的线程安全
     * 为确保buildRoutes线程安全，添加同步锁
     */
    public synchronized void buildRoutes() {
        clearRoutes();
        // 一次查询数据库，节省资源
        List<ApiInfo> services = apiRepository.getAll();
        log.info("开始构建动态路由，共有{}个服务", services.size());

        services.forEach(service -> {
            // 服务编号
            String serviceId = service.getServiceId();
            // 服务URI
            String routePath = service.getRoutePath();
            // 断言
            String requestPath = service.getRequestPath();

            try{
                URI uri = UriComponentsBuilder.fromHttpUrl(routePath).build().toUri();
                routesBuilder.route(serviceId,
                        r -> r.path(requestPath)
                                .filters(f -> f.stripPrefix(1)) // 过滤器规则
                                .uri(uri));
            }catch (Exception e){
                log.error("路由配置错误，服务ID{},服务URI{}",serviceId,routePath,e);
            }
        });

        this.route = routesBuilder.build().getRoutes();
        gatewayRoutesRefresher.refreshRoutes();
        log.info("动态路由构建完成");
    }
}
